/*http server request流控制
Created on 2020年05月10日
@author: zxyong 13738196011
 */

package com.zxy.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import com.zxy.common.Com_Para;
import com.zxy.model.Return_Value;

public class Request
{
	public String			strIP		= "";
	// 输入流
	private InputStream		input;
	private StringBuilder	uri			= new StringBuilder();
	private String[]		post_str	= null;
	public Return_Value		rv			= new Return_Value();

	public Request(InputStream inputStream)
	{
		this.input = inputStream;
	}

	public InputStream getInput()
	{
		return input;
	}

	public void setInput(InputStream input)
	{
		this.input = input;
	}

	public StringBuilder getUri()
	{
		return uri;
	}

	public void setUri(StringBuilder uri)
	{
		this.uri = uri;
	}

	public String[] getPost_str()
	{
		if(post_str == null)
			post_str = new String[0];
		return post_str;
	}

	public void setPost_str(String post_str[])
	{
		this.post_str = post_str;
	}

	// 从套接字中读取字符信息
	public void parse() throws UnsupportedEncodingException
	{
		StringBuffer request = new StringBuffer(2048000);
		int i = -1;
		try
		{
			/** 一次性读取 **/
			byte[] Bytes = new byte[204800];// this.input.available()
			i = this.input.read(Bytes,0,Bytes.length);
			if(i != -1)
			{
				byte[] bytem = new byte[i];
				for(int j = 0;j < i;j++)
				{
					bytem[j] = Bytes[j];
				}
				request.append(new String(bytem,Com_Para.U_CODE));
			}

			// 获取get数据 解码后数据
			this.uri = parseUri(new StringBuilder(request.toString()));
			// 获取post数据,为原始数据
			String[] strCheck = PostData(request.toString());
			// 未解码前先判断post数据长度
			if(strCheck[0] != "" && Integer.valueOf(strCheck[0].split(":")[1].trim()) == strCheck[1].getBytes(Com_Para.U_CODE).length)
			{
				// 解码post数据
				post_str = URLDecoder.decode(strCheck[1],Com_Para.U_CODE).split("&");// strCheck[1].split("&");
				if(!strCheck[1].equals(""))
				{
					// 解码post数据
					this.uri.append("&" + java.net.URLDecoder.decode(strCheck[1],Com_Para.U_CODE));
				}
			}
			else if(strCheck[0] != "" && strCheck[1].length() != Integer.valueOf(strCheck[0].split(":")[1].trim()) && Integer.valueOf(strCheck[0].split(":")[1].trim()) > 0)
			{
				/** 再次读取Post **/
				while(strCheck[1].length() < Integer.valueOf(strCheck[0].split(":")[1].trim()))
				{
					Bytes = new byte[204800];// this.input.available()];
					i = this.input.read(Bytes,0,Bytes.length);
					if(i != -1)
					{
						byte[] bytem = new byte[i];
						for(int j = 0;j < i;j++)
						{
							bytem[j] = Bytes[j];
						}
						String strtemPost = new String(bytem);
						request.append(strtemPost);
						strCheck[1] += strtemPost;
					}
					else
					{
						break;
					}
				}
				// 解码post数据
				post_str = URLDecoder.decode(strCheck[1],Com_Para.U_CODE).split("&");
				if(!strCheck[1].equals(""))
				{
					// 解码post数据
					this.uri.append("&" + URLDecoder.decode(strCheck[1],Com_Para.U_CODE));
				}
			}
		}
		catch(IOException e)
		{
			System.out.println("request error:" + e.getMessage());
			rv.s_result = 0;
			rv.err_desc.delete(0,rv.err_desc.length());
			rv.err_desc.append(e.getMessage());
		}
	}

	/*
	 * 这里我们自己模拟读取一行，因为如果使用API中的BufferedReader时，它是读取到一个回车换行后
	 * 才返回，否则如果没有读取，则一直阻塞，这就导致如果为POST请求时，表单中的元素会以消息体传送，
	 * 这时，消息体最末按标准是没有回车换行的，如果此时还使用BufferedReader来读时，则POST提交
	 * 时会阻塞。如果是POST提交时我们按照消息体的长度Content-Length来截取消息体，这样就不会阻塞
	 */
	@SuppressWarnings("unused")
	private StringBuilder readLine(InputStream is,int contentLe) throws IOException
	{
		StringBuffer request = new StringBuffer(204800);
		byte[] readByte = {-1};
		int total = 0;
		if(contentLe != 0)
		{
			do
			{
				readByte[0] = (byte)is.read();
				if(readByte[0] != -1)
				{
					request.append(new String(readByte,Com_Para.U_CODE));
					total++;
				}
			}
			while(total < contentLe && readByte[0] != -1);// 消息体读还未读完
		}
		else
		{
			String strTemStr = "";
			do
			{
				readByte[0] = (byte)is.read();
				if(readByte[0] == -1 && strTemStr.equals(""))
					return new StringBuilder("\r\n");
				else if(readByte[0] != -1)
					strTemStr += new String(readByte,Com_Para.U_CODE);
			}
			while(readByte[0] != 10 && readByte[0] != -1);
			request.append(strTemStr);
		}
		return new StringBuilder(request.toString());
	}

	private String[] PostData(String requestString) throws UnsupportedEncodingException
	{
		String[] strResult = {"",""};
		if(requestString.indexOf(Com_Para.Inf_Name) != -1 || requestString.indexOf(Com_Para.web_Name[0]) != -1 || requestString.indexOf(Com_Para.web_Name[1]) != -1)
		{
			String[] strTem = requestString.split("\r\n");
			if(strTem[0].split(" ").length > 1 && (strTem[0].split(" ")[0].equals("POST") || strTem[0].split(" ")[0].equals("OPTIONS")))
			{
				int Content_Length = -1;
				String strEnd = requestString.substring(requestString.length() - 4,requestString.length());
				if(!strEnd.equals("\r\n\r\n"))
				{
					strResult[1] = strTem[strTem.length - 1];
				}

				for(String strVal: strTem)
				{
					if(strVal.indexOf("post_param: ") == 0)
					{
						strResult[1] = strVal.substring(strVal.indexOf("post_param: ") + 12,strVal.length());
						strResult[0] = "Content-Length:" + String.valueOf(strResult[1].length());// strTem[3];
						break;
					}
					if(strVal.indexOf("Content-Length:") == 0)
					{
						Content_Length = Integer.valueOf(strVal.split(":")[1].trim());
						strResult[0] = "Content-Length:" + String.valueOf(Content_Length);
					}
					if(Content_Length > 0 && Content_Length == strResult[1].getBytes(Com_Para.U_CODE).length)
					{
						break;
					}
				}
			}
		}
		return strResult;
	}

	// 截取请求的url
	private StringBuilder parseUri(StringBuilder requestString) throws UnsupportedEncodingException
	{
		StringBuilder strResult = new StringBuilder();
		if(requestString.indexOf("/favicon.ico") != -1)
		{
			strResult.append("favicon.ico");
		}
		else if(requestString.toString().indexOf(Com_Para.Inf_Name) != -1)
		{
			for(String strTem: requestString.toString().split("\r\n"))
			{
				if(strTem.indexOf(Com_Para.Inf_Name) != -1)
				{
					/********* 临时注释 **********/
					if(strTem.split(" ")[1].indexOf("?") != -1)
						strResult.append(java.net.URLDecoder.decode((strTem.split(" ")[1]).split("\\?")[1],Com_Para.U_CODE));// \\?
					else strResult.append(java.net.URLDecoder.decode(strTem.split(" ")[1],Com_Para.U_CODE));
					break;
				}
			}
		}
		else if(requestString.toString().indexOf(Com_Para.web_Name[0]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[1]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[2]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[3]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[4]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[5]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[6]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[7]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[8]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[9]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[10]) != -1 || requestString.toString().indexOf(Com_Para.web_Name[11]) != -1)
		{
			for(String strTem: requestString.toString().split("\r\n"))
			{
				if(strTem.indexOf(Com_Para.web_Name[0]) != -1 || strTem.indexOf(Com_Para.web_Name[1]) != -1 || strTem.indexOf(Com_Para.web_Name[2]) != -1 || strTem.indexOf(Com_Para.web_Name[3]) != -1 || strTem.indexOf(Com_Para.web_Name[4]) != -1 || strTem.indexOf(Com_Para.web_Name[5]) != -1 || strTem.indexOf(Com_Para.web_Name[6]) != -1 || strTem.indexOf(Com_Para.web_Name[7]) != -1 || strTem.indexOf(Com_Para.web_Name[8]) != -1 || strTem.indexOf(Com_Para.web_Name[9]) != -1 || strTem.indexOf(Com_Para.web_Name[10]) != -1 || strTem.indexOf(Com_Para.web_Name[11]) != -1)
				{
					String strT = strTem.split(" ")[1];
					if(strT.indexOf("?") == -1)
						strResult.append(java.net.URLDecoder.decode(strTem.split(" ")[1],Com_Para.U_CODE));
					else strResult.append(java.net.URLDecoder.decode(strT.substring(0,strT.indexOf("?")),Com_Para.U_CODE));
					break;
				}
			}
		}
		else if(requestString.toString().length() > 10)
			strResult.append(java.net.URLDecoder.decode(requestString.toString(),Com_Para.U_CODE));
		return strResult;
	}
}